﻿using System;
using System.Collections.Generic;
using Hopscotch.Common;
using Hopscotch.Common.Contracts.AppService;
using Hopscotch.Common.Contracts.EnqService;
using Hopscotch.Domain.Common.Enums;
using Hopscotch.Domain.Common.StateTracking;
using Hopscotch.Domain.Enquiry;
using Hopscotch.Domain.Finance;
using Hopscotch.Presentation.Common;
using Hopscotch.Presentation.Common.Constants;
using Hopscotch.Presentation.Common.Events;
using Hopscotch.Presentation.Common.Threading;
using Hopscotch.Presentation.Controls.DataProviders;
using Microsoft.Practices.Prism.PubSubEvents;
using Microsoft.Practices.Prism.Interactivity.InteractionRequest;

namespace Hopscotch.Presentation.TradeModule.ViewModels
{
    public class TradeViewModel : ToolViewModel<Trade, int>, ITradeViewModel
    {
        private const string TradeViewTitle = "Trade";
        private const int DefaultLotSize = 1;

        private readonly IEventAggregator eventAggregator;
        private readonly IDispatcher dispatcher;
        private readonly IShellContext workspaceContext;

        private readonly ITradeEnqService tradeEnqService;
        private readonly IInstrumentDataProvider instrumentDataProvider;
        private readonly IPriceControlDataProvider priceControlDataProvider;

        public IList<TradeActivity> TradeActivityValues { get; private set; }

        public InteractionRequest<INotification> ErrorNotificationRequest { get; private set; }

        public TradeViewModel()
        {
        }

        public TradeViewModel(
            IEventAggregator eventAggregator,
            IDispatcher dispatcher,
            IShellContext workspaceContext,
            ITradeService tradeService,
            ITradeEnqService tradeHubClient,
            IInstrumentDataProvider instrumentDataProvider,
            IPriceControlDataProvider priceControlDataProvider)
            : base(dispatcher, tradeService)
        {
            this.eventAggregator = eventAggregator;
            this.dispatcher = dispatcher;
            this.workspaceContext = workspaceContext;
            this.tradeEnqService = tradeHubClient;

            //Child-control data providers
            this.instrumentDataProvider = instrumentDataProvider;
            this.priceControlDataProvider = priceControlDataProvider;

            //Interaction requests
            this.ErrorNotificationRequest = new InteractionRequest<INotification>();

            //Subscribe to events
            this.eventAggregator.GetEvent<InteropBroadcastEvent>().Subscribe(InteropBroadcastReceived, ThreadOption.BackgroundThread);
            SelectedInteropReactState = InteropReactState.Green;

            //Set Defaults
            TradeActivityValues = new List<TradeActivity>() { TradeActivity.Buy, TradeActivity.Sell };
            this.ViewTitle = TradeViewTitle;
            Uri uri;
            this.Icon16Uri = Uri.TryCreate(IconPaths.Wallet16, UriKind.Absolute, out uri) ? uri : null;

            //Create/Bind to model
            SetModel(null);
        }

        public IInstrumentDataProvider InstrumentDataProvider { get { return instrumentDataProvider; } }
        public IPriceControlDataProvider PriceControlDataProvider { get { return priceControlDataProvider; } }


        public int? TradeId
        {
            get
            {
                if (this.Model != null &&
                    this.Model.ChangeTracker.State != ObjectState.Added)
                    return Model.Id;

                return null;
            }
        }

        public Instrument Instrument
        {
            get { return Model.Instrument; }
            set
            {
                if (Model.Instrument == value)
                    return;

                Model.Instrument = value;

                UpdateInstrument(value);

                Validate();

                RaisePropertyChanged();
            }
        }

        private void UpdateInstrument(Instrument instrument)
        {
            if (instrument == null)
            {
                Model.InstrumentId = null;
                TradeCurrency = null;
                LotSize = DefaultLotSize;
            }
            else
            {
                Model.InstrumentId = instrument.Id;

                var instrumentEnq = Model.Instrument as EquityInstrument;
                if (instrumentEnq != null)
                {
                    TradeCurrency = instrumentEnq.DefaultCurrency;
                    LotSize = instrumentEnq.LotSize;
                }
            }

        }

        public decimal Quantity
        {
            get { return Model.Qty; }
            set
            {
                if (Model.Qty == value)
                    return;

                Model.Qty = value;

                Validate();

                RaisePropertyChanged();
            }
        }

        public decimal Price
        {
            get { return Model.Price; }
            set
            {
                if (Model.Price == value)
                    return;

                Model.Price = value;

                Validate();

                RaisePropertyChanged();
            }
        }

        public string TradeCurrency
        {
            get { return Model.TradeCcy; }
            set
            {
                if (Model.TradeCcy == value)
                    return;

                Model.TradeCcy = value;

                Validate();

                RaisePropertyChanged();
            }
        }

        public TradeActivity TradeActivity
        {
            get { return Model.Activity; }
            set
            {
                if (Model.Activity == value)
                    return;

                Model.Activity = value;

                Validate();

                RaisePropertyChanged();
            }
        }

        public decimal Commission
        {
            get { return Model.Commission; }
            set
            {
                if (Model.Commission == value)
                    return;

                Model.Commission = value;

                Validate();

                RaisePropertyChanged();
            }
        }

        public DateTime TradeDate
        {
            get { return Model.TradeDt; }
            set
            {
                if (Model.TradeDt == value)
                    return;

                Model.TradeDt = value;

                Validate();

                RaisePropertyChanged();
            }
        }

        public DateTime ValueDate
        {
            get { return Model.ValueDt; }
            set
            {
                if (Model.ValueDt == value)
                    return;

                Model.ValueDt = value;

                Validate();

                RaisePropertyChanged();
            }
        }

        private decimal total;
        public decimal Total
        {
            get { return total; }
            set
            {
                if (total == value)
                    return;

                total = value;

                Validate();

                RaisePropertyChanged();
            }
        }

        //todo, link AccountId
        private string account;
        public string Account
        {
            get { return account; }
            set
            {
                if (account == value)
                    return;

                account = value;
                //Model.Account = value;//zxzx

                Validate();

                RaisePropertyChanged();
            }
        }

        public string Memo
        {
            get { return Model.Memo; }
            set
            {
                if (Model.Memo == value)
                    return;

                Model.Memo = value;

                Validate();

                RaisePropertyChanged();
            }
        }

        public decimal TickSize
        {
            get { return 1; }
        }

        private int lotSize = DefaultLotSize;
        public int LotSize
        {
            get { return lotSize; }
            set
            {
                if (lotSize == value)
                    return;

                lotSize = value;
                RaisePropertyChanged();
            }
        }


        public override void OnValidate()
        {
            if (Quantity < 0)
            {
                AddError("Quantity", "Quantity can't be negative");
            }
            if (LotSize > 0 && (Quantity % LotSize > 0))
            {
                AddWarning("Quantity", string.Format("Quantity {0} is not a multiple of the lot size {1}", Quantity, LotSize));
            }
            if (Price < 0)
            {
                AddError("Price", "Price can't be negative");
            }

            if (IsSavePressed)
            {
                if (this.Instrument == null)
                    AddError("Instrument", "Instrument not set");

                if (TradeCurrency == null)
                    AddError("TradeCurrency", "Trade Currency not set");

                if (Quantity == 0)
                    AddError("Quantity", "Quantity can't be zero");

                if (Price == 0)
                    AddError("Price", "Price can't be zero");
            }
        }


        private bool IsInteropReadyToAccept(InteropBroadcastPayload interopBroadcastPayload)
        {
            if (IsBusy || IsNotifyVisible)
                return false;

            if (SelectedInteropReactState == InteropReactState.Red)
            {
                //Ignore all interops when in 'Red' State
                return false;
            }
            if (SelectedInteropReactState != InteropReactState.Green &&
                interopBroadcastPayload.WorkSpaceId != workspaceContext.WorkspaceId)
            {
                //Ignore global interops if not in 'Green' react state
                return false;
            }

            return true;
        }

        public void InteropBroadcastReceived(InteropBroadcastPayload interopBroadcastPayload)
        {
            if (!IsInteropReadyToAccept(interopBroadcastPayload))
                return;

            int tradeId = interopBroadcastPayload.GetIntId(EntityType.Trade);
            if (tradeId > 0)
            {
                Trade trade = tradeEnqService.GetWithInstrument(tradeId).Result;
                SetModel(trade);
                ToolEditMode = ToolEditMode.None;
            }
        }

        protected override Trade CreateNewEntity()
        {
            var trade = new Trade();
            trade.TradeDt = DateTime.Now.Date;
            trade.ValueDt = DateTime.Now.Date;

            return trade;
        }

        /// <summary>
        /// Raise method the ErrorNotification event and trigger any subscribing InteractionRequestTrigger's
        /// </summary>
        public override void RaiseErrorNotification(string errorMessage, Exception exception)
        {
            IsNotifyVisible = true;
            this.ErrorNotificationRequest.Raise(
               new Notification { Content = errorMessage, Title = "Error" },
               c => { IsNotifyVisible = false; } );
        }

    }
}

